//-------------------------------------------------------------------------------------------------
// Copyright (c) Bradford W. Mott and Flare Contributors
// North Carolina State University, Department of Computer Science
// The IntelliMedia Group
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//-------------------------------------------------------------------------------------------------

using Flare.Geom;

namespace Flare.Display
{
    /// <summary>
    /// The Sprite class provides a display list object that can display graphics
    /// as well as contain children. A sprite is similar to a movie clip; however,
    /// it does not contain a timeline.
    /// </summary>
    public class Sprite : DisplayObjectContainer
    {
        /// <summary>
        /// Graphics object associated with the sprite.
        /// </summary>
        public Graphics graphics { get;
            /* \cond */ internal set; /* \endcond */ }

        /// <summary>
        /// Create a new instance of the Sprite class.
        /// </summary>
        public Sprite()
        {
            this.graphics = new Graphics();
        }

        /// <summary>
        /// Allow the user to drag the sprite until stopDrag is called or until
        /// another sprite is made draggable.
        /// </summary>
        public void StartDrag(bool lockCenter = false, Rectangle? bounds = null)
        {
            NativeWindow.windowActiveForScripts.StartSpriteDrag(this, lockCenter, bounds);
        }

        /// <summary>
        /// Stop dragging the sprite.
        /// </summary>
        public void StopDrag()
        {
            NativeWindow.windowActiveForScripts.StopSpriteDrag();
        }

        internal override bool HitTest(float x, float y, bool shapeFlag, bool evaluateChildren)
        {
            // Check the sprite's graphics to see if there's a hit there or not
            if (graphics.HitTest(GlobalToLocal(new Point(x, y)), shapeFlag))
            {
                return true;
            }
            else if (evaluateChildren)
            {
                // See if there's a hit on any of the container's children
                return base.HitTest(x, y, shapeFlag, evaluateChildren);
            }
            else
            {
                return false;
            }
        }

        internal override void Render(RenderContext context)
        {
            if (!this.visible || this.isMask)
            {
                return;
            }

            if (this.mask != null)
            {
                context.PushMask(this.mask);
            }

            if (this.graphics.ContainsPaths)
            {
                context.SetupMasks();

                this.graphics.Render(transform.concatenatedMatrix,
                    transform.concatenatedColorTransform);
            }

            base.Render(context);

            if (this.mask != null)
            {
                context.PopMask();
            }
        }

        internal override void RenderAsMask(RenderContext context)
        {
            this.graphics.RenderAsMask(transform.concatenatedMatrix);
            base.RenderAsMask(context);
        }

        /// <summary>
        /// Return a clone of the Sprite with a deep copy of any mutable members.
        /// </summary>
        public override object Clone()
        {
            Sprite clone = (Sprite)base.Clone();

            // Deep copy the graphics
            clone.graphics = new Graphics(this.graphics);

            // Use copied buttonMode value

            return clone;
        }
    }
}